﻿//_______________________________________________________________________________________________________________________
// Copy Right (c) 2010, 2011 SapiensIT Consulting GmbH, all rights reserved
//_______________________________________________________________________________________________________________________
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//_______________________________________________________________________________________________________________________
// PROJECT:     sapiens.at.SharePoint (SharePoint 2010/V4)
//_______________________________________________________________________________________________________________________
// VERSION:     2.0
//_______________________________________________________________________________________________________________________
// DESCRIPTION: 
//_______________________________________________________________________________________________________________________
// LICENSE:     Different licens Types apply to different file types:
//               - Source code files are governed by the MICROSOFT PUBLIC LICENSE (Ms-PL)
//               - Binary files are governed by MSDN CODE GALLERY BINARY LICENSE
//               - Documentation files are governed by CREATIVE COMMONS ATTRIBUTION 3.0 LICENSE
//
//               The licenses can be found at the projects source location.
//               If you do not agree, don't use it!
// 
//_______________________________________________________________________________________________________________________
// Start SharePoint Branding, visit http://www.cliggin.com! Visit us on http://www.sapiens.at! Tell your friends! 
//_______________________________________________________________________________________________________________________
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint;
using QB = Sapiens.at.SharePoint.Utils.QueryBuilder;
using Sapiens.at.SharePoint.Entities;
using Sapiens.at.SharePoint.Security;
using Sapiens.at.SharePoint.Utils;
using Sapiens.at.SharePoint.Controls;
using Res = Sapiens.at.SharePoint.Resources.Sapiens_SharePoint;

namespace Sapiens.at.SharePoint.Forms
{
    /// <summary>
    /// Base class with a standard implementation for a listitem form.
    /// </summary>
    public class BaseForm : UserControl
    {
        /// <summary>
        /// The upper save button
        /// </summary>
        protected SaveButtonEx UpperSaveButton = null;

        /// <summary>
        /// The lower save button
        /// </summary>
        protected SaveButtonEx LowerSaveButton = null;

        /// <summary>
        /// The list field iterator
        /// </summary>
        protected ListFieldIteratorEx ListFieldIterator = null;

        /// <summary>
        /// A field that will be checked to ensure that it is unique inside the list.
        /// </summary>
        protected string UniqueField { get; set; }

        /// <summary>
        /// The controlmode of the listfielditerator.
        /// </summary>
        protected SPControlMode FormMode
        {
            get { return ListFieldIterator.ControlMode; }
        }

        /// <summary>
        /// The panel to add the informationbar
        /// </summary>
        protected Panel PanelInformationBar = null;

        /// <summary>
        /// Allow the redirection to the Source after the SPContext.Current.ListItem has been updated
        /// </summary>
        protected bool AllowRedirection
        {
            get { return UpperSaveButton.AllowRedirection; }
            set
            {
                UpperSaveButton.AllowRedirection = value;
                LowerSaveButton.AllowRedirection = value;
            }
        }
        
        /// <summary>
        /// Initializes the save buttons and assigns click event handlers
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            Res.Culture = System.Globalization.CultureInfo.GetCultureInfo(1033);
            Res.ResourceManager.GetResourceSet(Res.Culture, false, false);
            base.OnLoad(e);
            UpperSaveButton.Visible = FormMode != SPControlMode.Display;
            LowerSaveButton.Visible = FormMode != SPControlMode.Display;
            UpperSaveButton.Text = Res.SaveButtonText;
            LowerSaveButton.Text = Res.SaveButtonText;
            UpperSaveButton.OnBeforeUpdating += new EventHandler(UpperSaveButton_OnBeforeUpdating);
            LowerSaveButton.OnBeforeUpdating += new EventHandler(UpperSaveButton_OnBeforeUpdating);
            UpperSaveButton.OnValidSave += new EventHandler(UpperSaveButton_OnValidSave);
            LowerSaveButton.OnValidSave += new EventHandler(UpperSaveButton_OnValidSave);
            UpperSaveButton.OnInValidSave += new EventHandler(UpperSaveButton_OnInValidSave);
            LowerSaveButton.OnInValidSave += new EventHandler(UpperSaveButton_OnInValidSave);
        }
        void UpperSaveButton_OnInValidSave(object sender, EventArgs e)
        {
            OnInvalidSave();
        }
        void UpperSaveButton_OnValidSave(object sender, EventArgs e)
        {
            OnValidSave();
        }
        void UpperSaveButton_OnBeforeUpdating(object sender, EventArgs e)
        {
            OnBeforUpdating();
        }
        /// <summary>
        /// Gets called if the page is valid. Override this to perform special actions.
        /// </summary>
        protected virtual void OnValidSave() { }
        /// <summary>
        /// Gets called if the page is not valid. Override this to perform special actions.
        /// </summary>
        protected virtual void OnInvalidSave() { }
        /// <summary>
        /// Gets called before the ListItem is updated
        /// </summary>
        protected virtual void OnBeforUpdating()
        {
            AdditionalValidation();
        }

        /// <summary>
        /// If applicable finds the lookupfields that refer to the source and presets the value if possible.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            SPList sourceList;
            if (SPContext.Current.FormContext.FormMode == SPControlMode.New &&
                Page.Request.QueryString.AllKeys.Contains("Source"))
            {
                sourceList = SPContext.Current.Web.GetList(Page.Request.QueryString["Source"]);
                if ((sourceList != null) && (sourceList.ID != SPContext.Current.List.ID))
                {
                    // find lookupfield to set
                    var lookupFields = SPContext.Current.List.Fields.OfType<SPFieldLookup>().Where(f => !string.IsNullOrEmpty(f.LookupList) && new Guid(f.LookupList) == sourceList.ID);
                    var lookupField = (lookupFields.Count() > 0) ? lookupFields.First() : default(SPFieldLookup);
                    if (lookupField != default(SPFieldLookup))
                    {
                        // get the id from the SelectedID querystring parameter of the Source querystring parameter (nested)
                        var id = 0;
                        if (int.TryParse(System.Text.RegularExpressions.Regex.Match(Page.Request.QueryString["Source"], @"[\?|\&]SelectedID=(?<value>[^\?=\&\#]*)").Groups["value"].Value, out id))
                        {
                            // set the lookupvalue
                            BaseFieldControl bfc = ListFieldIterator.GetFieldControl(lookupField.InternalName);
                            if (bfc != null)
                            {
                                bfc.Value = new SPFieldLookupValue(id, "");
                                bfc.UpdateFieldValueInItem();
                            }
                        }
                    }
                }
            }
        }


        /// <summary>
        /// Performs additional validation.
        /// </summary>
        /// <remarks>
        /// Validates the <see cref="UniqueField"/>. Override this to add additional validation, but call the base
        /// method to get sure that the UniqueField gets validated.
        /// </remarks>
        protected virtual void AdditionalValidation()
        {
            if (!IsFieldUnique(UniqueField))
            {
                //not unique
                BaseFieldControl bfc = ListFieldIterator.GetFieldControl(UniqueField);
                bfc.IsValid = false;
                bfc.ErrorMessage = Res.ErrorNotUnique;
            }
            Page.Validate();
        }

        /// <summary>
        /// Checks for an other listitem with an equal value in the <see cref="UniqueField"/>.
        /// </summary>
        /// <param name="internalName">The name of the field that has to be unique</param>
        /// <returns>true, if there is no other listitem with the same value; otherwise false</returns>
        protected virtual bool IsFieldUnique(string internalName)
        {
            if (string.IsNullOrEmpty(internalName)) { return true; }

            IQueryBuilderExpression excludeSelf = null;
            if (ListFieldIterator.ListItem.ID > 0)
            {
                excludeSelf = QB.Neq<int>(Entity.ID_, ListFieldIterator.ListItem.ID);
            }
            SPQuery query = new SPQuery().Where(QB.And(QB.Eq<string>(UniqueField, Convert.ToString(ListFieldIterator.ListItem[UniqueField])), excludeSelf));
            query.RowLimit = 1;

            // search with elevated privileges to get all items
            bool result = true;
            Permissions.RunWithElevatedPrivileges(SPContext.Current.Web, delegate(SPWeb pWeb, SPListItem pItem)
            {
                result = pWeb.Lists[ListFieldIterator.List.ID].GetItems(query).Count == 0;
            });
            return result;
        }

        /// <summary>
        /// Returns the first childcontrol of type T.
        /// </summary>
        /// <typeparam name="T">Type of the control to find</typeparam>
        /// <param name="parentControl">The control to start the search</param>
        /// <returns>the first control found or default(T) if no control was found</returns>
        public T FindControl<T>(Control parentControl)
        {
            T retType = default(T);
            foreach (var c in parentControl.Controls)
            {
                if (c.GetType().FullName == typeof(T).FullName || c.GetType().IsSubclassOf(typeof(T)))
                    return (T)c;
                if ((c as Control).HasControls()) retType = FindControl<T>((c as Control));
                if (retType != null) return retType;
            }
            return retType;
        }

        /// <summary>
        /// Returns the first parent control of type T.
        /// </summary>
        /// <typeparam name="T">Type of the control to find</typeparam>
        /// <param name="control">The control to start the search</param>
        /// <returns>the first control found or default(T) if no control found</returns>
        public T FindParent<T>(Control control)
            where T : Control
        {
            while (control != null)
            {
                if (control.GetType().FullName == typeof(T).FullName) return (T)control;
                control = control.Parent;
            }
            return default(T);
        }
    }
}
